﻿using System.Collections.ObjectModel;

namespace XDCCManager.Model
{
	public class ActionQueueContext : BaseModel
	{
		public ActionQueueContext()
		{
			Actions = new ObservableCollection<Actions.ActionGroup>();
			if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
			{
				Model.Actions.ActionGroup group = new Actions.ActionGroup();
				Packs.IPack created = new Packs.NewPack() { Description = "Filename", Size = 35565 };
				group.Actions.Add(new Model.Actions.CreateAction(created as Packs.NewPack) { Progress = 25 });
				Packs.IPack parent = created;
				created = new Packs.EditedPack() { Description = "New description", Note = "New note", Source = parent };
				(parent as Packs.INavigable).Destination = created;
				group.Actions.Add(new Model.Actions.EditAction(created as Packs.EditedPack) { Progress = 45 });
				parent = created;
				created = new Packs.MovedPack() { Source = parent };
				(parent as Packs.INavigable).Destination = created;
				group.Actions.Add(new Model.Actions.MoveAction(created as Packs.MovedPack) { Progress = 76 });
				parent = created;
				created = new Packs.DeletedPack() { Source = parent };
				(parent as Packs.INavigable).Destination = created;
				group.Actions.Add(new Model.Actions.DeleteAction(created as Packs.DeletedPack));
				Actions.Add(group);
			}
		}

		public ObservableCollection<Actions.ActionGroup> Actions { get; private set; }

		public void AddAction(Actions.IAction action)
		{
			if (action is Actions.IPackAction)
				AddPackAction(action as Actions.IPackAction);
			else if (action is Actions.IFileAction)
				AddFileAction(action as Actions.IFileAction);
		}

		private void AddPackAction(Actions.IPackAction action)
		{
			Packs.IPack source = GetSource(action.Change);
			Model.Actions.ActionGroup addInGroup = null;
			bool actionFound = false;
			foreach (var group in Actions)
			{
				foreach (var groupAction in group.Actions)
				{
					if (groupAction is Actions.IPackAction)
					{
						if (action.Change == (groupAction as Actions.IPackAction).Change)
						{
							actionFound = true;
							break;
						}
						if (source == GetSource((groupAction as Actions.IPackAction).Change))
						{
							addInGroup = group;
							break;
						}
					}
					// TODO: groupAction is FileAction and source is Create.
				}
				if (actionFound || (addInGroup != null))
					break;
			}
			if (!actionFound)
			{
				addInGroup = AddActionInternal(action, addInGroup);
			}
		}

		private Model.Actions.ActionGroup AddActionInternal(Actions.IAction action, Actions.ActionGroup addInGroup)
		{
			if (addInGroup == null)
			{
				addInGroup = new Actions.ActionGroup();
				addInGroup.PropertyChanged += addInGroup_PropertyChanged;
				Actions.Add(addInGroup);
			}
			int insertIndex = Attributes.ActionOrderAttribute.ComputeInsertIndex(addInGroup, action);
			if (addInGroup.Actions.Count > 0)
				insertIndex = System.Math.Max(1, insertIndex);
			addInGroup.Actions.Insert(insertIndex, action);
			return addInGroup;
		}

		void addInGroup_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "FirstAction")
			{
				if ((sender as Actions.ActionGroup).FirstAction == null)
				{
					(sender as Actions.ActionGroup).PropertyChanged -= addInGroup_PropertyChanged;
					Actions.Remove(sender as Actions.ActionGroup);
				}
			}
		}

		private void AddFileAction(Actions.IFileAction action)
		{
			throw new System.NotImplementedException();
		}

		private Packs.IPack GetSource(Packs.IPack pack)
		{
			while ((pack is Packs.INavigable) && ((pack as Packs.INavigable).Source != null))
				pack = (pack as Packs.INavigable).Source;
			return pack;
		}
	}
}
